昨天講的是一段假規則怎麼騙過我。今天講這個專案的起點,一個看起來完全相反的問題:
我們的票卡全都是真的,而且寫得很詳細。但我看不懂。
「之前票卡大多是 AI 開票,但實際很少成員看得懂這張卡在做什麼?我需要怎麼測試?修改範圍有哪些?」
我第一次看到這句話的時候,以為「看不懂」的意思是寫得太少、太模糊。
不是。我手上那些卡,問題幾乎都不是寫太少。
而且我後來發現,「看不懂」有兩種,長得完全不一樣。
先說一張卡,以下稱卡 A。
它的標題和描述乍看都很正常,驗收條件也列得出來。如果只看卡面,我會覺得這張卡我可以測。
但這張卡從開出來、RD 實作,到推給我測試,中間隔了一段不短的時間。而那段時間裡,RD 一直在留言區留紀錄。
卡 A 有 32 則留言。
而那些留言,也是 AI 寫的。內容大概長這樣(我照原始結構改寫、去識別化):
真根因(機制已證):這是表格套件 21.2.2 的「level-short」狀態 —— group 列在 auto-group 欄的值來自
rowNode.groupData[autoColId];當這個 entry 缺失時,getValue回undefined,於是 PR #xxxx 加的groupRowComparator收到(undefined, undefined)→ 每一對都回 0 → stable sort → group 列凍在原始資料順序。修法:在
XxxGrid的autoGroupColumnDef補一個valueGetter,比照另一個報表早就有的同一道 guard,group 列回String(node.key)。健康路徑上完全不作用。
我想先講一句公道話:這則留言的品質非常高。 它有機制、有對照組、有證據,還誠實標出了自己沒能重現的部分。如果我是 RD,我會非常感謝寫這則留言的人。
但我是 QA。
而且還有一層更現實的問題——QA 不一定有看程式的權限。這些留言裡的檔名、行號、函式名,對我來說不是「可以去查的線索」,它們是不可驗證的斷言。它說那裡是 undefined,我只能相信它是 undefined。
再加上一件很實務的事:這張卡是全英文的,而且卡面資訊不夠,要往下讀完整串留言才知道到底改了什麼。
所以我收到卡片之後的第一個決定,不是「開始讀」。
是「丟給 AI 讀」。
第一步:AI 讀完,吐給我一份 AC。
看起來很合理。條列、分項、每一項都寫得像驗收條件該有的樣子。
第二步:我拿著那份 AC 去手動測。
然後卡住了——我看不懂我手上的測項。
不是看不懂字面,是不知道那一項到底要我幹嘛。它給的方法,有些要去打 API,有些要在瀏覽器主控台輸入指令。那些做法只有看過程式的人才會知道為什麼要這樣測,而它預設我看過。
RD 在留言裡也有一段是這種等級的,他直接請我在主控台跑一行程式、把輸出貼回去:
請在你重現問題的那個檢視上,開 DevTools console 跑這行,把輸出貼給我:
gridApi.forEachNode(n => { if (n.group && n.level===0) console.log(n.level, n.key, JSON.stringify(n.groupData)); });
- 若
groupData缺了那一格 → level-short 確認,上面的修法就是正解。- 若
groupData有值卻仍不翻 → 是另一種機制,我會繼續追。
他寫得很清楚,連兩種結果各代表什麼都先講了。這已經是很體貼的做法。
但你看得出來這需要什麼:要能判斷輸出,你得先知道 groupData 是什麼。
要幹嘛?怎麼做?怎樣是對、怎樣是錯?——這四個問題,我手上那份 AI 生的 AC,一個都沒真正回答。
路 A:一路交給 AI 走到底。
既然留言我讀不懂,由 AI 解讀;既然測試方法要有程式知識,由 AI 給;既然我判斷不了輸出,由 AI 判讀;最後那份 QA 回報,當然也是 AI 整理的。
流程會跑完,每個環節都有產出,格式漂亮。而真正的 QA 不知道剛剛發生了什麼事。
路 B:去問人。
我選了 B。直接問 RD、問開票的人。
這個選擇讓票卡顯得很沒用——一張寫了 32 則留言的卡,最後我還是靠嘴巴問。但它是最實際、也最快的做法。
我後來才意識到,路 B 真正的意思是:
那張卡在整段流程裡,一次都沒有被當成「資訊來源」使用過。
它被當成 AI 的輸入、被當成一個「這件事要去找誰問」的指標,就是沒有被當成它原本該是的東西——一份看了就能做事的文件。
而路 A 更危險,因為它看起來是成功的。有 AC、有測試紀錄、有結論,卡片會被移到下一個河道。
只有一件事沒發生:沒有人驗證過。
而不能驗證的東西,不算測過。
這句話會貫穿接下來的 28 天。
第二種看不懂,長得完全不一樣。以下稱卡 B。
這張卡不是 PM 開的。它的描述第一句話就是檔名和行號:
A1. Week 分組是 ISO 週一開始,頁面其他地方都是週日開始
getXxxColumnDefs.ts:905→GGGG-[W]WW(ISO,週一起算)xxxGroupByConfig.ts:26→DOW_ORDER週一優先- 但
XxxHeader.tsx:28,31的 preset 是 "This week (Sun - Today)"
一樣的,我先講公道話:如果這張卡是給 RD 看的,它非常好。 它直接告訴你問題在第幾行、為什麼衝突、要改哪裡。RD 會謝謝你。
但這張卡後來是要走到 QA 和 PM 手上的。
而從 QA / PM 的角度讀它,你會遇到兩件事:
第一,你看不出最終成果是什麼。 它從頭到尾在描述「現在有什麼問題」,沒有一句在描述「修完之後它應該長什麼樣」。沒有一張預期畫面的圖。要測的話,我得自己把 22 個問題描述,反推成 22 個預期結果。
第二,你甚至可能看不懂一開始的問題是什麼。 「ISO 週一起算 vs locale 週日起算」這件事,講到最後對使用者的影響是什麼?要讀到第五行才出現。而更多項目,連第五行都沒有。
還有規模的問題。這張卡的描述分成三段:
22 個項目 + 4 項待補,一張卡。
然後是驗收標準。它有 checklist,但第一條是這樣寫的:
待確認:週起始日、空值 token、日期格式與 quick range 的產品規則。
驗收標準的第一條,是「還沒決定」。
你的原話我覺得沒辦法寫得更好了,直接放:
一整個就是不知道目的地還要啟程的油輪。我怕他根本是鐵達尼號。
卡 A 的天書在留言區,卡 B 的天書在描述裡。但它們壞在同一個地方:
這張卡沒有指定讀者。
卡 A 的留言區,實際讀者是 RD 和他的 AI——那是一份工作日誌,寫得很好,只是不是寫給我的。卡 B 的描述,實際讀者也是 RD。
而這兩張卡,都會走到三種人手上:PM 要排優先序、QA 要測、RD 要改。
一張卡想同時服務三種人,結果是只服務了其中一種。
更麻煩的是,另外兩種人不會舉手說「我看不懂」。他們會說「喔好」,然後各自去猜、去問、去找 AI——而猜錯不會當場爆炸,會等到上線之後。
那現在怎麼辦?現況是這樣:
「整理後人工放到專案管理系統,通常是開票後負責人有空就重新敘述並搬移。沒有一個標準流程。」
這句話有兩個詞我盯了很久。
「有空」 —— 這件事永遠是第二順位。它不在任何人的 sprint 裡,沒有人追蹤完成率,它發生在所有正事做完之後,而正事永遠做不完。
「重新敘述」 —— 這份知識在轉手時被重新產生了一次。負責人不是搬運,是憑自己的理解重寫。寫得好不好、記得多少、漏了什麼,取決於是誰寫、那天狀態如何、離開卡過了多久。
於是整套系統建立在兩個前提上:搬運的人剛好有空,而且剛好記得。
兩個都不可靠。
如果只有十張卡,答案很簡單:排一個下午,一張一張重寫,順手把格式訂下來。這是正確做法,而且做得到。
看板上超過一百張。
「100+ 票我人工沒辦法。」
這句話聽起來像在喊累,但它其實是一個架構判斷。它排除掉的不只是「我自己重寫」,還包括所有逐張人工處理的方案:排班輪流、要求 RD 補齊、請 PM 審核。任何規模是 O(票數 × 人力) 的方案,在這個量級都跑不動——而且票還在長。
剩下的選項只有一個:讓機器去讀那一百多張卡,然後回答問題。
但這裡有一個我當時還沒想清楚的問題:
如果卡 A 的留言連我都讀不懂、卡 B 的描述根本沒寫最終成果,那讓一個 AI 去讀這一百多張卡,它讀到的會是什麼?
它會不會也「看起來讀懂了」?
(那是 Phase 2 的事。)
我後來把這件事收斂成一句我自己在用的準則:
一張卡的品質,不看它寫了多少,看讀的人能不能開始動作。
卡 A 寫了 32 則留言,卡 B 寫了 22 個項目。兩張都非常詳細,而我讀完都沒辦法開始測。
那我最後怎麼測的?
卡 A,我去問人。卡 B——22 個項目、驗收標準第一條是「待確認」——我也是去問人。
兩張卡壞的方式完全不一樣,一張的天書在留言區、一張的天書在描述裡,但結局一模一樣:我靠嘴巴問出來的資訊,比卡片上寫的還有用。
我不覺得這是我偷懶。在那個當下,問人就是正確答案:它最快、最準,而且問到的是活的——對方會告訴你「這一項其實不用測,因為還沒決定」,那是卡片永遠不會寫的東西。
但這個做法有三個代價,而且每一個都會隨票數放大:
所以這個專案某種意義上就是一句話:
我想把「去問人」那一段,變成可以被問第二次。
明天講那三個問題:PM 問什麼、QA 問什麼、RD 問什麼。
這三段是我在寫任何一行程式之前先寫下來的東西。我現在回頭看,它比後面所有技術決策都重要——因為它是唯一決定「做出來的東西有沒有用」的那一步。